/*
 * COPYRIGHT Ericpol Telecom sp. z o.o. 2006
 * The copyright to the computer program(s) herein is the property of
 * Ericpol Telecom. The programs may be used and/or copied only with written
 * permission from Ericpol Telecom or in accordance with the terms and
 * conditions stipulated in the agreement under which the
 * programs have been supplied.
 *
 * $Id: SippWrapper.java 663 2007-07-02 14:53:41Z jacek.kolezynski $
 */
package logmatcher.sipp;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import logmatcher.executor.Executor;
import logmatcher.report.ReportEvent;
import logmatcher.report.ReportHandler;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;


/**
*  Class executing sipp and redirecting its output to logger.
 */
public class SippWrapper {
    //~ Static fields/initializers -------------------------------------------------------------------------------------

    /** Class logger. */
    private static final Log LOGGER = LogFactory.getLog(SippWrapper.class);

    /** End of test log message. */
    static final String END_OF_TEST = "--- END ---";

    //~ Instance fields ------------------------------------------------------------------------------------------------

    /** The executor object. */
    private Executor executor;

    /** The report handler object. */
    private ReportHandler reportHandler;

    /** Counter of successful calls. */
    private int success;

    /** Counter of failure calls. */
    private int failure;
    
    private Process process;
    
    private StreamRedirector streamRedirector;
    
    
    //~ Methods --------------------------------------------------------------------------------------------------------

    /**
    *  Executes sipp command with given parameters. If some of the parameters is a flag it should have null
    *  value in the map.
    *
    *  @param props sipp parameters
    */
    public void execute(List args) {
        StringBuilder cmd = new StringBuilder("sipp ");

        for (Iterator iter = args.iterator(); iter.hasNext();) {
			String element = (String) iter.next();
		    cmd.append(element);
            cmd.append(" ");
		}        
        
        try {
        	LOGGER.info("Starting sipp process with command: "+ cmd.toString());
            process = Runtime.getRuntime().exec(cmd.toString());
            LOGGER.info("Process returned");
        } catch (IOException e) {
            LOGGER.error("Cannot start process using command: " + cmd.toString(), e);

            reportHandler.receiveEvent(
                new ReportEvent(ReportEvent.Type.FAILED, "Cannot start process using command: " + cmd.toString()));

            executor.taskEnded();
        }

        streamRedirector = new StreamRedirector(process.getInputStream());
        streamRedirector.start();
    }


    /**
    *  Sets reference to the executor object.
    *
    *  @param executor the executor
    */
    public void setExecutor(Executor executor) {
        this.executor = executor;
    }


    /**
    *  Sets reference to the report handling object.
    *
    *  @param reportHandler the report handler
    */
    public void setReportHandler(ReportHandler reportHandler) {
        this.reportHandler = reportHandler;
    }

    //~ Inner Classes --------------------------------------------------------------------------------------------------

    /**
    *  Class used to redirect stream to logger.
     */
    class StreamRedirector implements Runnable {
        //~ Static fields/initializers ---------------------------------------------------------------------------------

        /** End of test log message. */
        static final String END_OF_TEST = "--- END ---";

        //~ Instance fields --------------------------------------------------------------------------------------------

        /** Reader used for reading data from input stream. */
        private BufferedReader br;

        //~ Constructors -----------------------------------------------------------------------------------------------

/**
        *  Creates a new StreamRedirector object.
        *
        *  @param inputStream the input stream
        *  @param filename the file name
        */
        public StreamRedirector(InputStream inputStream) {
            br = new BufferedReader(new InputStreamReader(inputStream));
        }

        //~ Methods ----------------------------------------------------------------------------------------------------
        
        public void start(){
            new Thread(this).start();
        }

        /**
        *  Reads data from input stream and writes it to the output.
        */
        public void run() {
            String line;

            try {
                line = br.readLine();

                while (line != null) {
                    if (!line.equals("")) {
                        LOGGER.info(line);
                    }

                    if (line.contains("Successful call")) {
                        success = getNumberAfterLastDelimeter(line, "|");
                    } else if (line.contains("Failed call")) {
                        failure = getNumberAfterLastDelimeter(line, "|");
                    } else if (line.contains("Call Length")) {
                        ReportEvent.Type result;
                        String message = executor.getTestCaseName();

                        if (success > 0) {
                            result = ReportEvent.Type.PASSED;
                            message += " - sipp: Test completed successfuly";
                            LOGGER.debug("sipp finished successfuly");
                        } else {
                            result = ReportEvent.Type.FAILED;
                            message += " - sipp: Test failed";
                            LOGGER.debug("sipp finished with failure");
                        }

                        reportHandler.receiveEvent(new ReportEvent(result, message));

                        LOGGER.info(END_OF_TEST);
                        executor.taskEnded();
                        process.destroy();
                    }

                    line = br.readLine();
                }
            } catch (IOException e) {
                LOGGER.error("Error while reading process output", e);

                reportHandler.receiveEvent(
                    new ReportEvent(ReportEvent.Type.FAILED, "Error while reading process output"));

                executor.taskEnded();
            }
        }


        /**
        *  Helper method reading number from string after last specified delimeter.
        *
        *  @param line the line to be analyzed
        *  @param delim the delimeter
        *
        *  @return TODO: DOCUMENT ME!
        */
        private int getNumberAfterLastDelimeter(String line, String delim) {
            String numString = line.substring(line.lastIndexOf(delim) + 1, line.length()).trim();
            int num = 0;

            try {
                num = Integer.parseInt(numString);
            } catch (NumberFormatException e) {
                LOGGER.error("Error while analyzing process output", e);
            }

            return num;
        }
    }
}
